///////////////////////// 泛型之Hello World /////////////////////////

// function identity(arg: number): number{
//     return arg;
// }

// function identity1(arg: any): any{
//     return arg;
// }

// 使用泛型定义一个函数
// function identity<T>(arg: T): T {
//     return arg;
// }

// // 调用泛型函数方法1
// let output = identity<string>("myString");

// // 调用泛型函数方法2
// let output2 = identity("myString");

///////////////////////// 使用泛型变量 /////////////////////////

// function loggingIdentity<T>(arg: T[]): T[] {
//     console.log(arg.length);
//     return arg;
// }

// function loggingIdentity2<T>(arg: Array<T>): Array<T>{
//     console.log(arg.length);
//     return arg;
// }

///////////////////////// 泛型类型 /////////////////////////


//// 1

// function identity<T>(arg:T):T{
//     return arg;    
// }

// let myIdentity: <T>(arg:T) => T = identity;

//// 2

// function identity<T>(arg: T): T{
//     return arg;
// }

// let myIdentity: <U>(arg: U) => U = identity;

//// 3
// function identity<T>(arg: T):T{
//     return arg;
// }
// let myIdentity: {<T>(arg:T):T} = identity

//// 4

// interface GenericIdentityFn{
//     <T>(arg:T):T;
// }

// function identity<T> (arg: T):T{
//     return arg;
// }

// let myIdentity: GenericIdentityFn = identity;

///// 5

// interface GenericIdentityFn<T>{
//     (arg: T):T;
// }

// function identity<T>(arg:T):T{
//     return arg;
// }

// let myIdentity: GenericIdentityFn<number> = identity;

///////////////////////// 泛型类 /////////////////////////

// class GenericNumber<T> {
//     zeroValue: T;
//     add: (x: T, y: T) => T;
// }

// let myGenericNumber = new GenericNumber<number>();
// myGenericNumber.zeroValue = 0;
// myGenericNumber.add = function(x, y) { return x + y; };

// let stringNumeric = new GenericNumber<string>();
// stringNumeric.zeroValue = "";
// stringNumeric.add = function(x, y) { return x + y; };

// console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));


///////////////////////// 泛型约束 /////////////////////////

// interface Lengthwise {
//     length: number;
// }

// function loggingIdentity<T extends Lengthwise>(arg: T): T {
//     console.log(arg.length);  // Now we know it has a .length property, so no more error
//     return arg;
// }

// loggingIdentity(3);  // Error, number doesn't have a .length property

// loggingIdentity({length: 10, value: 3});

/////////// 在泛型约束中使用类型参数

// function getProperty(obj: T, key: K) {
//     return obj[key];
// }

// let x = { a: 1, b: 2, c: 3, d: 4 };

// getProperty(x, "a"); // okay
// getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.

/////////// 在泛型里使用类类型

//// 在TypeScript使用泛型创建工厂函数时，需要引用构造函数的类类型

// function create<T>(c: {new():T;}):T{
//     return new c();
// }

//// 一个更高级的例子，使用原型属性推断并约束构造函数与类实例的关系

// class BeeKeeper {
//     hasMask: boolean;
// }

// class ZooKeeper {
//     nametag: string;
// }

// class Animal {
//     numLegs: number;
// }

// class Bee extends Animal {
//     keeper: BeeKeeper;
// }

// class Lion extends Animal {
//     keeper: ZooKeeper;
// }

// function createInstance<A extends Animal>(c: new () => A): A {
//     return new c();
// }

// createInstance(Lion).keeper.nametag;  // typechecks!
// createInstance(Bee).keeper.hasMask;   // typechecks!